package com.lvm.app.controller;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.lvm.app.api.entity.LvmFileRec;
import com.lvm.app.api.entity.LvmTopicRec;
import com.lvm.app.config.LvmProperties;
import com.lvm.app.dao.LvmFileRecMapper;
import com.lvm.app.dto.FileTaskDTO;
import com.lvm.app.exception.BusinessException;
import com.lvm.app.file.TopicFileInfo;
import com.lvm.app.file.TopicFileSum;
import com.lvm.app.task.TaskInfo;
import com.lvm.app.task.VideoTask;
import com.lvm.app.task.VideoTaskExecutor;
import com.lvm.app.task.VideoTaskHolder;
import com.lvm.app.util.CreateMd5;
import com.lvm.app.util.R;
import com.lvm.app.util.UploadInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.bytedeco.javacv.FrameGrabber;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/file")
@Api(value = "/file",tags = "文件管理")
public class LvmFileRecController implements ApplicationContextAware {
    @Autowired
    private LvmFileRecMapper lvmFileRecMapper;
    @Autowired
    private LvmProperties lvmProperties;
    @Autowired
    private VideoTaskHolder taskHolder;

    private ApplicationContext applicationContext;

    private Logger logger =  LoggerFactory.getLogger(LvmFileRecController.class);

    @GetMapping("/queryTask")
    @ApiOperation("检索任务列表")
    @ResponseBody
    public R<List<Map>> queryTask(String taskId){
        List<Map> s =  taskHolder.queryTask(taskId).stream().map((item)->{
            Map res = new HashMap();
            res.put("taskId",item.getTaskId());
            res.put("taskName",item.getTaskName());
            res.put("taskType",item.getTaskType());
            res.put("topics",item.getTopics());
            res.put("curMessage",item.getCurMessage());
            res.put("status",item.getStatus());
            return res;
        }).collect(Collectors.toList());
        return R.ok(s);
    }

    @PostMapping("/fileIterator")
    @ApiOperation("文件查找")
    public R<TaskInfo> fileIterator(String dir,String taskName){
        TopicFileSum fileUtil = new TopicFileSum();
        File dirFile = new File(dir);
        List<TopicFileInfo> fileInfoList = fileUtil.fileDirIterator(dirFile);
        VideoTask task = new VideoTask(lvmProperties.fileDir,applicationContext);
        task.setTopics(fileInfoList);
        task.setTaskName(taskName);
        task.setTaskType(1);
        taskHolder.addTask(task);
        TaskInfo taskInfo = new TaskInfo();
        taskInfo.setTaskId(task.getTaskId());
        taskInfo.setTaskName(task.getTaskName());
        return R.ok(taskInfo);
    }


    @PostMapping("/upload")
    @ResponseBody
    @ApiOperation("文件上传")
    public R<UploadInfo> upload(MultipartFile file){
        String fileName = file.getOriginalFilename();
        String ext = fileName.substring(fileName.lastIndexOf("."));
        String urlFileName = UUID.randomUUID()+ext;
        LvmFileRec fileUpload = new LvmFileRec();
        try{
            StringBuilder fileMD5 = CreateMd5.createMd5(file);
            List<LvmFileRec> fileRec = lvmFileRecMapper.selectList(Wrappers.<LvmFileRec>lambdaQuery().eq(LvmFileRec::getMd5,fileMD5.toString()));
            if(fileRec!=null&&fileRec.size()>0){
                UploadInfo upload = new UploadInfo();
                upload.setSuffix(fileRec.get(0).getSuffix());
                upload.setFileName(fileName);
                upload.setMd5(fileMD5.toString());
                upload.setUrl("/file/load?path="+fileRec.get(0).getFileUrl());
                return R.ok(upload);
            }else{
                String[] dir = saveFile(file,urlFileName);
                String url = dir[0]+urlFileName;
                fileUpload.setMd5(fileMD5.toString());
                fileUpload.setFileDir(url);
                fileUpload.setFileNo(UUID.randomUUID().toString());
                fileUpload.setFileUrl(url);
                fileUpload.setSize(file.getSize());
                fileUpload.setSuffix(ext);
                lvmFileRecMapper.insert(fileUpload);
                UploadInfo upload = new UploadInfo();
                upload.setSuffix(fileUpload.getSuffix());
                upload.setFileName(fileName);
                upload.setMd5(fileMD5.toString());
                upload.setUrl("/file/load?path="+fileUpload.getFileUrl());
                return R.ok(upload);
            }

        }catch (Exception e){
            throw new BusinessException(e.getMessage());
        }

    }
    @GetMapping("/load")
    @ApiOperation("文件加载")
    public void load(String fileNo,HttpServletRequest request, HttpServletResponse response){
        LvmFileRec rec = lvmFileRecMapper.selectOne(Wrappers.<LvmFileRec>lambdaQuery().eq(LvmFileRec::getFileNo,fileNo));
        String filePath = "";
        if(rec!=null){
            filePath = lvmProperties.getFileDir()+File.separator+rec.getFileDir();
        }else{
            return;
        }
        RandomAccessFile inputStream = null;
        OutputStream out = null;
        try {
            out = response.getOutputStream();
            File file = new File(filePath);
            inputStream = new RandomAccessFile(file,"r");
            response.setHeader("content-type", "application/octet-stream");
            response.setHeader("Content-Disposition", "attachment;fileName=" + file.getName());// 设置文件名
            response.setHeader("ETag", file.getName());
            response.setHeader("Last-Modified", "Wed, 24 Feb 2021 07:00:31 GMT");
            if(file.getName().toLowerCase().indexOf("mp4")>=0||file.getName().toLowerCase().indexOf("mov")>=0){
                try{
                    this.sendVideo(request,response,out,inputStream,file.getName());
                    return;
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
            if(file.getName().toLowerCase().indexOf("png")>=0||file.getName().toLowerCase().indexOf("jpg")>=0||file.getName().toLowerCase().indexOf("jpeg")>=0){
                response.setHeader("content-type", "image/png");
            }
            try{
                byte[] cache = new byte[2048];
                int len = 0;
                while ((len = inputStream.read(cache))>-1){
                    out.write(cache);
                }
                out.flush();
            }catch (Exception e){
                e.printStackTrace();
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try{
                if(out!=null){
                    out.close();
                }

            }catch (Exception s){
               // s.printStackTrace();
            }
            try{
                if(inputStream!=null){
                    inputStream.close();
                }
            }catch (Exception s){

            }
        }

    }

    private void sendVideo(HttpServletRequest request, HttpServletResponse response,OutputStream out,RandomAccessFile randomFile, String fileName) throws FileNotFoundException, IOException {
        try{
            long contentLength = randomFile.length();
            String range = request.getHeader("Range");
            int start = 0, end = 0;
            if(range != null && range.startsWith("bytes=")){
                String[] values = range.split("=")[1].split("-");
                start = Integer.parseInt(values[0]);
                if(values.length > 1){
                    end = Integer.parseInt(values[1]);
                }
            }
            int requestSize = 0;
            if(end != 0 && end > start){
                requestSize = end - start + 1;
            } else {
                requestSize = Integer.MAX_VALUE;
            }

            byte[] buffer = new byte[4096];
            if(fileName.indexOf("mp4")>=0||fileName.indexOf("mov")>=0){
                response.setContentType("video/mp4");
            }else if(fileName.indexOf("mp3")>=0){
                response.setContentType("audio/mp3");
            }else if(fileName.indexOf("wav")>=0){
                response.setContentType("audio/wav");
            }
            response.setHeader("Accept-Ranges", "bytes");
            //第一次请求只返回content length来让客户端请求多次实际数据
            if(range == null){
                response.setHeader("Content-length", contentLength + "");
            }else{
                //以后的多次以断点续传的方式来返回视频数据
                response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);//206
                long requestStart = 0, requestEnd = 0;
                String[] ranges = range.split("=");
                if(ranges.length > 1){
                    String[] rangeDatas = ranges[1].split("-");
                    requestStart = Integer.parseInt(rangeDatas[0]);
                    if(rangeDatas.length > 1){
                        requestEnd = Integer.parseInt(rangeDatas[1]);
                    }
                }
                long length = 0;
                if(requestEnd > 0){
                    length = requestEnd - requestStart + 1;
                    response.setHeader("Content-length", "" + length);
                    response.setHeader("Content-Range", "bytes " + requestStart + "-" + requestEnd + "/" + contentLength);
                }else{
                    length = contentLength - requestStart;
                    response.setHeader("Content-length", "" + length);
                    response.setHeader("Content-Range", "bytes "+ requestStart + "-" + (contentLength - 1) + "/" + contentLength);
                }
            }

            int needSize = requestSize;
            randomFile.seek(start);
            while(needSize > 0){
                int len = randomFile.read(buffer);
                try{
                    if(needSize < buffer.length){
                        out.write(buffer, 0, needSize);
                    } else {
                        out.write(buffer, 0, len);
                        if(len < buffer.length){
                            break;
                        }
                    }
                }catch (IOException e){
                    return;
                }
                needSize -= buffer.length;
            }
        }catch (Exception e){
            e.printStackTrace();
        }

    }
    public String makeDir(){
        LocalDateTime now  =  LocalDateTime.now();
        String dir =  File.separator+now.getYear()+File.separator+now.getMonth().getValue()+File.separator;
        File dirFile = new File(lvmProperties.getFileDir()+dir);
        if(!dirFile.exists()){
            dirFile.mkdirs();
        }
        return dir;
    }

    public String[] saveFile(MultipartFile file,String fileName) throws IOException {
        String dir =  makeDir();
        File fil = new File(lvmProperties.getFileDir()+dir+fileName);
        try{
            file.transferTo(fil);
            String posterUrl = null;
            return new String[]{dir,posterUrl};
        }catch (Exception e){
            throw e;
        }

    }


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
